#include "Player.h"
#include "Engine.h"
#include "GameConstants.h"

#define MAX_BULETS 10

const Vector3<float> Player::CAMARA_SHIFT = Vector3<float>(0,20,0);
const float Player::MOVMENT_SPEED = 50;
const float Player::MAX_SPEED = 100;

const float Player::JUMP_POWER = 200;
const float Player::GRAVITY = 160;

Player::Player(Vector3<float> pos):
	_canJump(true),
	_moving(false)
{
	_model = new Colider(GameConstants::MODELS["Cube"], pos, 20);
	_model->Scale() = Vector3<float>(5,10,5);
	_model->_color = MyColor(0,0,1,1);

	_view = new Camara(_model->Position() + CAMARA_SHIFT, 60, 2, 0.1, 10000);
	_view->Activate();
	_view->Rotation(Quaternion::NO_ROTATION);
}


Player::~Player(void)
{
	delete _view;
	delete _model;
}

Colider* Player::Model()
{
	return _model;
}

void Player::Update()
{
	// first check if ground colision
	if(_model->Position().Y() <= 10)
	{
		if(!_canJump)
		{
		Translate( Vector3<float>(0, 10.0f - _model->Position().Y() , 0) );
		_model->Velocity().setY(0);
		_canJump = true;
		}
		if(!_moving)
		{
			_model->Velocity() = Vector3<float>::ZERO;
		}
	}
	else
	{
		_model->Velocity() += Vector3<float>(0,-GRAVITY,0) * Engine::dt;
	}

	KeyboardInput();
	MouseInput();

	Vector3<float> veloNoY(_model->Velocity());
	veloNoY.setY(0);
	
	if(veloNoY.Magnitude() > MAX_SPEED)
	{
		veloNoY = veloNoY.Normal() * MAX_SPEED;
		veloNoY.setY(_model->Velocity().Y());
		_model->Velocity() = veloNoY;
	}
	
	for(int i = 0; i < MAX_BULETS; i++)
	{
		_bullets[i].Update();
	}

	//Translate(_model->Velocity() * Engine::dt);

	_view->Run();
	_model->Update();

	_view->TranslateTo(_model->Position() + CAMARA_SHIFT);
}

// draws the bullets that need to be drawn
void Player::Draw()
{
	_model->Draw();

	for(int i = 0; i < MAX_BULETS; i++)
	{
		if(_bullets[i].Active())
		{
			_bullets[i].Draw();
		}
	}
}

Vector3<float> Player::Position()
{
	return _model->Position();
}

void Player::TranslateTo(Vector3<float> destination)
{
	_model->TranslateTo(destination);
	_view->TranslateTo(_model->Position() + CAMARA_SHIFT);
}

void Player::Translate(Vector3<float> distance)
{
	_model->Translate(distance);
	_view->TranslateTo(_model->Position() + CAMARA_SHIFT);
}

// have the player manage were it is in the tree
void Player::TreeManagment(OctTree* tree)
{
	if(!tree->ObjectMoved(_model))
	{
		tree->addGameObject(_model);
	}
	
	for(int i = 0; i < MAX_BULETS; i++)
	{
		if(_bullets[i].Active() && !tree->ObjectMoved(_bullets[i].Model()))
		{
			tree->addGameObject(_bullets[i].Model());
		}
	}
}

// the player shoots a bullet from it view
void Player::Shoot()
{
	for(int i = 0; i < MAX_BULETS; i++)
	{
		if(!_bullets[i].Active())
		{
			_bullets[i].Fire(_view->Position(), _view->Forward() * 10);
			break;
		}
	}
}

// run the keyboard imput to detetction and results
void Player::KeyboardInput()
{
	_moving = false;
	Vector3<float> groundMovment(0,0,0);

	if(glutKeyboardManager::KeyPresed('w')) // w
	{ 
		_moving = true;
		Vector3<float> fwrd = _view->Rotation() * Vector3<float>(0,0,-1); 
		fwrd.setY(0);
		groundMovment += fwrd.Normal();
	}
	if(glutKeyboardManager::KeyPresed('a')) // a
	{ 
		_moving = true;
		//_player.Translate(Vector3<float>(-0.005f,0,0));
		Vector3<float> fwrd = _view->Rotation() * Vector3<float>(0,0,-1); 
		fwrd = fwrd.Cross(Vector3<float>(0,1,0));
		fwrd.setY(0);
		groundMovment += fwrd.Normal();
	}
	if(glutKeyboardManager::KeyPresed('s')) // s
	{ 
		_moving = true;
		Vector3<float> fwrd = _view->Rotation() * Vector3<float>(0,0,1); 
		fwrd.setY(0);
		groundMovment += fwrd.Normal();
	}
	if(glutKeyboardManager::KeyPresed('d')) // d
	{ 
		_moving = true;
		Vector3<float> fwrd = _view->Rotation() * Vector3<float>(0,0,-1); 
		fwrd = fwrd.Cross(Vector3<float>(0,1,0)) * -1;
		fwrd.setY(0);
		groundMovment += fwrd.Normal();
	}
	if(_canJump && glutKeyboardManager::KeyPresed(' '))
	{
		_model->Velocity() += Vector3<float>(0,JUMP_POWER,0);
		_canJump = false;
	}
	if(glutKeyboardManager::FirstPress('.')) /// exit the game
	{

		exit(0);
	}


	if(groundMovment.X() != 0 || groundMovment.Y() != 0)
	{
		_model->Velocity() += groundMovment.Normal() * MOVMENT_SPEED * Engine::dt;
	}

}

// run the mouse imput detetion and results
void Player::MouseInput()
{
	int deltaX = glutMouseManager::XChange();
	int deltaY = glutMouseManager::YChange();

	if(deltaX != 0 || deltaY != 0)
	{
		Camara tmp(*_view);
		tmp.Rotate(Quaternion::AxisAngle(Vector3<float>(1,0,0), 0.005f * -(float)deltaY));

		if(abs(tmp.Forward().Y()) <= 0.99) // then actualy rotate
		{
			_view->Rotate(Quaternion::AxisAngle(Vector3<float>(1,0,0), 0.005f * -(float)deltaY));
		}

		_view->RotateGlobal(Quaternion::AxisAngle(Vector3<float>(0,1,0), 0.005f * -(float)deltaX));
		
		glutWarpPointer(700, 350);
		glutMouseManager::MouseMoved(700 ,350);
	}

	if(glutMouseManager::ButtonPresed(1)) // center click
	{
		_view->Rotation(Quaternion::NO_ROTATION);
	}

	if(glutMouseManager::SinglePress(0)) // right click SinglePress
	{
		this->Shoot();
		double xJerk = 5 - (rand() % 10);
		double yJerk = 5 - (rand() % 10);
		_view->Rotate(Quaternion::AxisAngle(Vector3<float>(1,0,0), 0.005f * yJerk));
		_view->RotateGlobal(Quaternion::AxisAngle(Vector3<float>(0,1,0), 0.005f * xJerk));
	}
}